package com.un.ebs.finance.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.un.ebs.core.config.K3Config;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.core.util.WebResult;
import com.un.ebs.core.util.WebUtils;
import com.un.ebs.finance.AccountTypeEnum;
import com.un.ebs.finance.WebService1;
import com.un.ebs.finance.WebService1Soap;
import com.un.ebs.finance.dto.CertificateModel;
import com.un.ebs.finance.dto.CustomerDto;
import com.un.ebs.finance.dto.FDetailDto;
import com.un.ebs.finance.dto.K3Result;
import com.un.ebs.finance.service.FinanceSyncService;
import com.un.ebs.inventory.domain.EntRelationExt;
import com.un.ebs.inventory.domain.InventoryNoteExt;
import com.un.ebs.inventory.domain.InventoryNoteItemExt;
import com.un.ebs.inventory.dto.InventoryNoteVo;
import com.un.ebs.inventory.enums.BusinessRelationTypeEnum;
import com.un.ebs.inventory.enums.InventoryTypeEnum;
import com.un.ebs.inventory.service.BusinessRelationService;
import com.un.ebs.inventory.service.InventoryNoteService;
import com.un.ebs.inventory.service.InventoryService;
import com.un.ebs.invoice.domain.InvoiceNoteExt;
import com.un.ebs.invoice.enums.InvoiceTypeEnum;
import com.un.ebs.invoice.service.InvoiceNoteService;
import com.un.ebs.product.enums.ProductPurchaseTypeEnum;
import com.un.ebs.purchase.domain.PurchaseMonthSumExt;
import com.un.ebs.purchase.service.PurchaseOrderService;
import com.un.ebs.sale.domain.FinanceBySaleExt;
import com.un.ebs.sale.dto.SaleOrderVo;
import com.un.ebs.sale.service.SaleOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;

/**
 * @author liubo
 * @email liubocs@163.com
 * @date 2020/9/15 14:47
 */
@RestController
@RequestMapping("/finance")
@Api(value = "finance", tags = "")
public class SyncController {

    @Resource
    private BusinessRelationService businessRelationService;

    @Resource
    private PurchaseOrderService purchaseOrderService;

    @Resource
    private InventoryNoteService inventoryNoteService;

    @Resource
    private SaleOrderService saleOrderService;

    @Resource
    private InvoiceNoteService invoiceNoteService;

    @Resource
    private FinanceSyncService financeSyncService;

    @Resource
    private K3Config k3Config;

    private WebService1Soap soap;

    public SyncController() {
        if (this.soap == null) {
            try{
                WebService1 ws = new WebService1();
                soap = ws.getWebService1Soap();
            }catch (Exception e){
                System.out.println(e);
            }
        }
    }

    @PostMapping("syncBaseData")
    @ApiOperation("syncBaseData")
    public WebResult syncBaseData(@RequestParam BusinessRelationTypeEnum type) {
        WebService1 ws = new WebService1();
        WebService1Soap soap = ws.getWebService1Soap();
        for (EntRelationExt item : businessRelationService.query(null, type, -1, 1).getRecords()) {
            String strRet;
            switch (type) {
                case CUSTOMER:
                    strRet = soap.qureyCustomer(item.getCode().toString(), k3Config.getUserName(), k3Config.getPassword());
                    break;
                case SUPPLIER:
                    strRet = soap.qureySupplier(item.getCode().toString(), k3Config.getUserName(), k3Config.getPassword());
                    break;
                case DEFAULT:
                default:
                    throw new BusinessException("往来单位类别不正确。");
            }

            try {
                CustomerDto obj = JSON.parseObject(strRet).toJavaObject(CustomerDto.class);
                System.out.println(obj);
            } catch (JSONException e) {
                switch (type) {
                    case CUSTOMER:
                        strRet = soap.customer("0", item.getCode().toString(), item.getName(), k3Config.getUserName(), k3Config.getPassword());
                        break;
                    case SUPPLIER:
                        strRet = soap.supplier("0", item.getCode().toString(), item.getName(), k3Config.getUserName(), k3Config.getPassword());
                        break;
                    case DEFAULT:
                    default:
                        throw new BusinessException("往来单位类别不正确。");
                }

                System.out.println(strRet);
            }
        }

        return WebUtils.success();
    }

    @PostMapping("sync")
    @ApiOperation("syncAll")
    public WebResult sync(@RequestParam Integer accountYear, @RequestParam Integer accountMonth) {
        System.out.println("-----------------------------------客户基础数据同步开始：1/10");
        syncBaseData(BusinessRelationTypeEnum.CUSTOMER);

        System.out.println("---------------------------------供应商基础数据同步开始：2/10");
        syncBaseData(BusinessRelationTypeEnum.SUPPLIER);

        //采购入库
        System.out.println("--------------------------------------采购入库同步开始：3/10");
        syncPurchase(accountYear, accountMonth);

        //生产领料
        System.out.println("--------------------------------------生产领料同步开始：4/10");
        syncProductionBom(accountYear, accountMonth);

        //其它领料
        System.out.println("--------------------------------------其它领料同步开始：5/10");
        syncProductionOther(accountYear, accountMonth);

        //生产入库
        System.out.println("--------------------------------------生产入库同步开始：6/10");
        syncProductionIn(accountYear, accountMonth);

        //销售出库
        System.out.println("--------------------------------------销售出库同步开始：7/10");
        syncSaleOut(accountYear, accountMonth);

        //质保出库
        System.out.println("--------------------------------------质保出库同步开始：8/10");
        syncSaleService(accountYear,accountMonth);

        //销售发票
        System.out.println("--------------------------------------销售发票同步开始：9/10");
        syncSaleInvoice(accountYear, accountMonth);

        //采购发票
        System.out.println("--------------------------------------采购发票同步开始：10/10");
        syncPurchaseInvoice(accountYear, accountMonth);

        System.out.println("------------------------------------------同步完成！！！");
        return WebUtils.success();
    }

    @PostMapping("syncPurchase")
    @ApiOperation("syncPurchase")
    public WebResult syncPurchase(@RequestParam Integer accountYear, @RequestParam Integer accountMonth) {

        for (PurchaseMonthSumExt item : purchaseOrderService.queryMonthSum(accountYear, accountMonth)) {

            if (item.getPurchaseMoney() == 0) {
                continue;
            }

            double money = new BigDecimal(item.getPurchaseMoney()).setScale(2, RoundingMode.HALF_UP).doubleValue();
            CertificateModel m = CertificateModel.create("001", 0, DateUtils.parseDate(accountYear, accountMonth, 20), false);
            m.getModel().addDetail("1403", String.format("%s采购暂估", item.getEntName()), money, AccountTypeEnum.debit, FDetailDto.valueDept("1100"));
            m.getModel().addDetail("2202.01", String.format("%s采购暂估", item.getEntName()), money, AccountTypeEnum.credit, FDetailDto.valueSupplier(item.getEntCode().toString()));

            try {
                K3Result ret = syncCertificate(m);
            } catch (Exception e) {
                return WebUtils.error(e);
            }
        }

        return WebUtils.success();
    }

    @PostMapping("syncProductionIn")
    @ApiOperation("syncProductionIn")
    public WebResult syncProductionIn(@RequestParam int year, @RequestParam int month) {

        Double money = inventoryNoteService.queryCostMoney(InventoryTypeEnum.PRODUCTION_IN, year, month);
        CertificateModel m = CertificateModel.create("001", 0, DateUtils.parseDate(year, month, 20), false);
        m.getModel().addDetail("1405", String.format("本月生产入库"), money, AccountTypeEnum.debit, FDetailDto.valueDept("1100"));
        m.getModel().addDetail("5001.01", String.format("本月生产入库"), money, AccountTypeEnum.credit, FDetailDto.valueDept("1100"));

        try {
            K3Result ret = syncCertificate(m);
            //inventoryNoteService.updateFinanceCode(year, month, InventoryTypeEnum.PRODUCTION_IN, ret.getId(), ret.getCode());
        } catch (Exception e) {
            return WebUtils.error(e);
        }
        return WebUtils.success();
    }

    @PostMapping("syncProductionBom")
    @ApiOperation("syncProductionBom")
    public WebResult syncProductionBom(@RequestParam int year, @RequestParam int month) {

        double money = new BigDecimal(inventoryNoteService.queryCostMoney(InventoryTypeEnum.PRODUCTION_BOM_USER, year, month))
                .add(new BigDecimal(inventoryNoteService.queryCostMoney(InventoryTypeEnum.REPAIR_USER, year, month))).doubleValue();

        CertificateModel m = CertificateModel.create("001", 0, DateUtils.parseDate(year, month, 20), false);
        m.getModel().addDetail("5001.01", String.format("本月直接材料领用"), money, AccountTypeEnum.debit, FDetailDto.valueDept("1100"));
        m.getModel().addDetail("1403", String.format("本月直接材料领用"), money, AccountTypeEnum.credit, FDetailDto.valueDept("1100"));

        try {
            K3Result ret = syncCertificate(m);
            //inventoryNoteService.updateFinanceCode(year, month, InventoryTypeEnum.PRODUCTION_BOM_USER, ret.getId(), ret.getCode());
            //inventoryNoteService.updateFinanceCode(year, month, InventoryTypeEnum.REPAIR_USER, ret.getId(), ret.getCode());
        } catch (Exception e) {
            return WebUtils.error(e);
        }

        return WebUtils.success();
    }

    @PostMapping("syncProductionOther")
    @ApiOperation("syncProductionOther")
    public WebResult syncProductionOther(@RequestParam int year, @RequestParam int month) {
        double money = inventoryNoteService.queryCostMoney(InventoryTypeEnum.PRODUCTION_USER, year, month);
        if (money == 0) {
            return WebUtils.success("没有数据需要同步");
        }

        CertificateModel m = CertificateModel.create("001", 0, DateUtils.parseDate(year, month, 20), false);
        m.getModel().addDetail("5001.03.14", String.format("本月消耗品领用"), money, AccountTypeEnum.debit, FDetailDto.valueDept("1100"));
        m.getModel().addDetail("1403", String.format("本月消耗品领用"), money, AccountTypeEnum.credit, FDetailDto.valueDept("1100"));

        try {
            K3Result ret = syncCertificate(m);
            inventoryNoteService.updateFinanceCode(year, month, InventoryTypeEnum.PRODUCTION_USER, ret.getId(), ret.getCode());
        } catch (Exception e) {
            return WebUtils.error(e);
        }

        return WebUtils.success();
    }

    @PostMapping("syncSaleOut")
    @ApiOperation("syncSaleOut")
    public WebResult syncSaleOut(@RequestParam int year, @RequestParam int month) {
        try {
            FinanceBySaleExt note = saleOrderService.queryFinanceBySale(year, month);
            CertificateModel m = CertificateModel.create("001", 0, DateUtils.parseDate(year, month, 20), false);

            m.getModel().addDetail("1406", String.format("本月发出商品"), new BigDecimal(note.getCostMoney()).setScale(2,RoundingMode.HALF_UP).doubleValue(), AccountTypeEnum.debit, FDetailDto.valueDept("1100"));
            m.getModel().addDetail("1405", String.format("本月发出商品"), new BigDecimal(note.getProductionCostMoney()).setScale(2,RoundingMode.HALF_UP).doubleValue(), AccountTypeEnum.credit, FDetailDto.valueDept("1100"));
            m.getModel().addDetail("1403", String.format("本月发出商品"), new BigDecimal(note.getPurchaseCostMoney()).setScale(2,RoundingMode.HALF_UP).doubleValue(), AccountTypeEnum.credit, FDetailDto.valueDept("1100"));
            syncCertificate(m);
        } catch (Exception e) {
            return WebUtils.error(e.hashCode(), e.getMessage());
        }

        return WebUtils.success();
    }

    @PostMapping("syncSaleService")
    @ApiOperation("syncSaleService")
    public WebResult syncSaleService(@RequestParam int year, @RequestParam int month) {
        try {
            FinanceBySaleExt note = saleOrderService.queryFinanceByService(year, month);
            CertificateModel m = CertificateModel.create("001", 0, DateUtils.parseDate(year, month, 20), false);
            m.getModel().addDetail("6601.13.01", String.format("本月质保材料出库"), new BigDecimal(note.getCostMoney()).setScale(2,RoundingMode.HALF_UP).doubleValue(), AccountTypeEnum.debit, FDetailDto.valueDept("1100"));
            m.getModel().addDetail("1405", String.format("本月质保材料出库"), new BigDecimal(note.getProductionCostMoney()).setScale(2,RoundingMode.HALF_UP).doubleValue(), AccountTypeEnum.credit, FDetailDto.valueDept("1100"));
            m.getModel().addDetail("1403", String.format("本月质保材料出库"), new BigDecimal(note.getPurchaseCostMoney()).setScale(2,RoundingMode.HALF_UP).doubleValue(), AccountTypeEnum.credit, FDetailDto.valueDept("1100"));
            syncCertificate(m);
        } catch (Exception e) {
            return WebUtils.error(e.hashCode(), e.getMessage());
        }

        return WebUtils.success();
    }

    @PostMapping("syncSaleInvoice")
    @ApiOperation("syncSaleInvoice")
    public WebResult syncSaleInvoice(@RequestParam int year, @RequestParam int month) {

        financeSyncService.syncSaleInvoice(year,month,"1100");
        return WebUtils.success();
    }

    @PostMapping("syncPurchaseInvoice")
    @ApiOperation("syncPurchaseInvoice")
    public WebResult syncPurchaseInvoice(@RequestParam int year, @RequestParam int month) {

        financeSyncService.syncPurchaseInvoice(year,month,"1100");
        return WebUtils.success();
    }

    private void updateCertificate(CertificateModel model, String inventoryNoteId) {
        String ret = soap.certificate("1", JSONObject.toJSONString(model), k3Config.getUserName(), k3Config.getPassword());
        System.out.println(ret);
    }

    private K3Result syncCertificate(CertificateModel model) {
        String ret = soap.certificate("0", JSONObject.toJSONString(model), k3Config.getUserName(), k3Config.getPassword());
        if (JSONObject.parseObject(ret).containsKey("code")) {
            String code = JSONObject.parseObject(ret).get("code").toString();
            if ("1".equals(code)) {
                //成功
                System.out.println(String.format("id : %s , %s", JSONObject.parseObject(ret).get("id").toString(), model.getModel().getEntity().get(0).getExplanation()));
                return K3Result.getInstance(JSONObject.parseObject(ret).get("id").toString(), JSONObject.parseObject(ret).get("Number").toString());
            } else {
                //失败
                System.out.println(JSONObject.toJSONString(model));
                throw new BusinessException("同步失败：" + ret);
            }
        } else {
            System.out.println(JSONObject.toJSONString(model));
            throw new BusinessException("接口异常：" + ret);
        }
    }

    private void syncCertificate(CertificateModel model, String inventoryNoteId) {
        String ret = soap.certificate("0", JSONObject.toJSONString(model), k3Config.getUserName(), k3Config.getPassword());
        if (JSONObject.parseObject(ret).containsKey("code")) {
            String code = JSONObject.parseObject(ret).get("code").toString();
            if ("1".equals(code)) {
                inventoryNoteService.updateFinanceCode(inventoryNoteId, JSONObject.parseObject(ret).get("id").toString(), JSONObject.parseObject(ret).get("Number").toString());
                System.out.println(String.format("InventoryNoteId : %s ,  Finance Code : %s", inventoryNoteId, JSONObject.parseObject(ret).get("id").toString()));
            } else {
                System.out.println(JSONObject.toJSONString(model));
                System.out.println(String.format("InventoryNoteId : %s ,  message : %s", inventoryNoteId, JSONObject.parseObject(ret).get("state")));
                throw new BusinessException(JSONObject.parseObject(ret).get("state").toString());
            }
        } else {
            System.out.println(JSONObject.toJSONString(model));
            throw new BusinessException("接口异常：" + ret);
        }
    }

    private void syncInvoiceCertificate(CertificateModel model, String invoiceId) {
        String ret = soap.certificate("0", JSONObject.toJSONString(model), k3Config.getUserName(), k3Config.getPassword());
        if (JSONObject.parseObject(ret).containsKey("code")) {
            String code = JSONObject.parseObject(ret).get("code").toString();
            if ("1".equals(code)) {
                invoiceNoteService.updateFinanceCode(invoiceId, JSONObject.parseObject(ret).get("id").toString(), JSONObject.parseObject(ret).get("Number").toString());
                System.out.println(String.format("InventoryNoteId : %s ,  Finance Code : %s", invoiceId, JSONObject.parseObject(ret).get("id").toString()));
            } else {
                System.out.println(JSONObject.toJSONString(model));
                System.out.println(String.format("InventoryNoteId : %s ,  message : %s", invoiceId, JSONObject.parseObject(ret).get("state")));
                throw new BusinessException(JSONObject.parseObject(ret).get("state").toString());
            }
        } else {
            System.out.println(JSONObject.toJSONString(model));
            throw new BusinessException("接口异常：" + ret);
        }
    }
}
